home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgLangD.iso / BORLAND TURBO / OWLSRC.PAK / GAUGE.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  12.7 KB  |  444 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // Copyright (c) 1993, 1997 by Borland International, All Rights Reserved
  4. //
  5. //$Revision:   10.11  $
  6. //
  7. // Implementation of TGauge, a gauge user interface widget
  8. //----------------------------------------------------------------------------
  9. #include <owl/pch.h>
  10. #if !defined(OWL_GAUGE_H)
  11. # include <owl/gauge.h>
  12. #endif
  13. #if !defined(OWL_DC_H)
  14. # include <owl/dc.h>
  15. #endif
  16. #if !defined(OWL_COMMCTRL_H)
  17. # include <owl/commctrl.h>
  18. #endif
  19. #if !defined(WINSYS_UIMETRIC_H)
  20. # include <winsys/uimetric.h>
  21. #endif
  22. #include <stdio.h>
  23.  
  24. OWL_DIAGINFO;
  25.  
  26. DEFINE_RESPONSE_TABLE1(TGauge, TControl)
  27.   EV_WM_ERASEBKGND,
  28. END_RESPONSE_TABLE;
  29.  
  30. //
  31. // Don't know off the bat, native impl may not cut it. Decide later before
  32. // creation of the window
  33. //
  34. TNativeUse TGauge::ClassNativeUse = nuAttempt;
  35.  
  36. //
  37. // General constructor for a TGauge object - Use this constructor if you
  38. // are creating an object whose features might require that OWL provides
  39. // the underlying implementation. For example, a vertical progress bar.
  40. //
  41. // NOTE: This constructor default to a LedSpacing and LedThickness of 0,
  42. //       which OWL interpretes as a request for a solid/filled progress bar.
  43. //       You must explicitly invoke 'SetLed' with non-zero values if you 
  44. //       want otherwise.
  45. //
  46. TGauge::TGauge(TWindow*        parent,
  47.                const char far* title,
  48.                int             id,
  49.                int x, int y, int w, int h,
  50.                bool            isHorizontal,
  51.                int             margin,
  52.                TModule*        module)
  53. :
  54.   TControl(parent, id, title, x, y, w, h ? h : int(TUIMetric::CyVScroll), module)
  55. {
  56.   Min = 0;
  57.   Max = 100;
  58.   Step = 10;
  59.   Value = 0;
  60.   Margin = margin * TUIMetric::CxBorder;
  61.   IsHorizontal = isHorizontal;
  62.   LedSpacing = 0;
  63.   LedThick = 0;
  64.   BarColor = TColor::SysHighlight;
  65.   Attr.Style &= ~WS_TABSTOP;     
  66.   NativeUse = TCommCtrl::IsAvailable() ? ClassNativeUse : nuNever;
  67. }
  68.  
  69. //
  70. // Simplified constructor for a TGauge object--creates horizontal LED style
  71. // gauge using a system control when available. 
  72. //
  73. // NOTE: If you want to create a gauge with features not available from
  74. //       the common control, use the previous constructor, followed by
  75. //       calls to methods that specify the feature [ eg.
  76. //         SetHorizontal(false);]
  77. //
  78. TGauge::TGauge(TWindow*        parent,
  79.                int             id,
  80.                int x, int y, int w, int h,
  81.                TModule*        module)
  82. :
  83.   TControl(parent, id, "", x, y, w, h ? h : int(TUIMetric::CyVScroll), module)
  84. {
  85.   Min = 0;
  86.   Max = 100;
  87.   Step = 10;
  88.   Value = 0;
  89.   Margin = TUIMetric::CxBorder;
  90.   IsHorizontal = true;
  91.   Attr.Style &= ~WS_TABSTOP;     
  92.   LedSpacing = ((Attr.H - 2*Margin) * 2) / 3 + 2*Margin;  
  93.   LedThick = 100 * LedSpacing / (LedSpacing - 2*Margin);
  94.   BarColor = TColor::SysHighlight;
  95.   NativeUse = TCommCtrl::IsAvailable() ? ClassNativeUse : nuNever;
  96. }
  97.  
  98. //
  99. // Constructor for a resource gauge object.
  100. //
  101. // NOTE: This constructor defaults the 'LedSpacing' and 'LedThick' parameter
  102. //       to 10/90, which is interpreted by OWL as a request for the native
  103. //       implementation of the control [unless the common control library
  104. //       is not available]. If you need an emulated version of the control
  105. //       to be created from a dialog resource, you must ensure the following:
  106. //
  107. //       1. Change the control's class to 'OWL_Gauge' for 32-bit resources
  108. //       2. Explicitly invoke the method which triggers the emulation
  109. //          feature you're after. For example, if you want a filled 
  110. //          progress bar, call 'SetLed(0, 0)'. You may follow this by a
  111. //          'SetTitle("%d%%")' to have a percentage display.
  112. //
  113. TGauge::TGauge(TWindow*        parent,
  114.                int             resId,
  115.                TModule*        module)
  116. :
  117.   TControl(parent, resId, module)
  118. {
  119.   Min = 0;
  120.   Max = 100;
  121.   Step = 10;
  122.   Value = 0;
  123.   Margin = TUIMetric::CxBorder;
  124.   IsHorizontal = true;
  125.   LedSpacing = 10;
  126.   LedThick = 90;
  127.   BarColor = TColor::SysHighlight;
  128.   NativeUse = TCommCtrl::IsAvailable() ? ClassNativeUse : nuNever;
  129. }
  130.  
  131. //
  132. // Returns the class name of the native control or emulation
  133. // depending on NativeUse.
  134. //
  135. char far*
  136. TGauge::GetClassName()
  137. {
  138.   // Decide now, if we haven't already, whether to use Native control 
  139.   // for this based on settings & availability
  140.   //
  141.   // NOTE: The current assumptions are:
  142.   //    i. Any request for LedSpacing implies try to use the native 
  143.   //       implementation.
  144.   //   ii. Any request for LedSpacing of '0' implies emulate a filled
  145.   //       bar progress bar.
  146.   //  iii. Any request for a horizontal progress bar implies the use of
  147.   //       OWL's emulated version.
  148.   //
  149.   if ((NativeUse & nuSuggestion) >= nuDontCare && 
  150.       IsHorizontal    &&
  151.       LedSpacing >= 0 && 
  152.       LedThick >= 0   && 
  153.       TCommCtrl::IsAvailable())
  154.     NativeUse = TNativeUse(NativeUse | nuUsing);
  155.   else
  156.     NativeUse = TNativeUse(NativeUse & ~nuUsing);
  157.  
  158.   // NOTE: The current version of Workshop will generate 'msctls_progess32'
  159.   //       instead of 'msctls_progress' for 16-bit resources. This is 
  160.   //       probably a safe approach since the future of the 16-bit version
  161.   //       of the Common Control library is very bleak. So when we're 
  162.   //       emulating the control under 16-bit, we'll use 'msctls_progress32'
  163.   //       as the classname to make it easier to use the generated resource
  164.   //       script as-is. However, we cannot use this approach in 32-bit
  165.   //       since emulation and native must have unique class names. 
  166.   // SO:   If you need a feature that's not available from the common 
  167.   //       control library (such as *vertical* progress bars) and are using
  168.   //       the control within a resource, you will need to explicitly modify 
  169.   //       your resource script so that the progress bar is described as a 
  170.   //       custom control with the classname 'OWL_Gauge'.
  171.   //
  172.   return (NativeUse & nuUsing) ? PROGRESS_CLASS : "OWL_Gauge";
  173. }
  174.  
  175. //
  176. // Check & set the gauge range
  177. //
  178. void
  179. TGauge::SetRange(int min, int max)
  180. {
  181.   if (max <= min)
  182.     max = min+1;
  183.  
  184.   if ((NativeUse & nuUsing) && GetHandle()) {
  185.     if (!SendMessage(PBM_SETRANGE, 0, MkParam2(min, max)))
  186.       return; 
  187.   }
  188.  
  189.   Min = min;
  190.   Max = max;
  191. }
  192.  
  193. //
  194. // Set the step amount of the gauge for StepIt operations
  195. //
  196. void
  197. TGauge::SetStep(int step)
  198. {
  199.   if ((NativeUse & nuUsing) && GetHandle())
  200.     SendMessage(PBM_SETSTEP, step);
  201.  
  202.   Step = step;
  203. }
  204.  
  205. //
  206. // Set the value of the gauge
  207. //
  208. void
  209. TGauge::SetValue(int value)
  210. {
  211.   // Constrain value to be in the range "Min..Max"
  212.   //
  213.   if (value > Max)
  214.     value = Max;
  215.  
  216.   else if (value < Min)
  217.     value = Min;
  218.  
  219.   // Paint to new position, converting value to pixels
  220.   //
  221.   if (value != Value) {
  222.     if (GetHandle()) {
  223.       if (NativeUse & nuUsing)
  224.         SendMessage(PBM_SETPOS, value);
  225.       else
  226.         Invalidate(false);
  227.     }
  228.     Value = value;
  229.   }
  230. }
  231.  
  232. //
  233. // Change the value of the gauge given a delta
  234. //
  235. void
  236. TGauge::DeltaValue(int delta)
  237. {
  238.   if (!delta)
  239.     return;
  240.  
  241.   // Constrain delta such that Value stays in the range "Min..Max"
  242.   //
  243.   if (delta + Value > Max)
  244.     delta = Max - Value;
  245.  
  246.   else if (delta + Value < Min)
  247.     delta = Min - Value;
  248.  
  249.   if (GetHandle()) {
  250.     if (NativeUse & nuUsing) {
  251.       Value = (int)SendMessage(PBM_DELTAPOS, delta); // Take oportunity to sync
  252.       return;  // Bypass Value update below
  253.     }
  254.     // Paint to new position, converting value to pixels
  255.     //
  256.     else
  257.       Invalidate(false);
  258.   }
  259.  
  260.   Value += delta;
  261. }
  262.  
  263. //
  264. // Adjust active gauge value by step increment. Wrap around to Min of range
  265. // on overflow
  266. //
  267. void
  268. TGauge::StepIt()
  269. {
  270.   if (GetHandle()) {
  271.     if (NativeUse & nuUsing) {
  272.       SendMessage(PBM_STEPIT);
  273.     }
  274.     else {
  275.       if (Value + Step < Max)
  276.         DeltaValue(Step);
  277.       else
  278.         SetValue(Min);
  279.     }
  280.   }
  281. }
  282.  
  283. //
  284. // Set led parameters
  285. //
  286. void
  287. TGauge::SetLed(int spacing, int thickPercent)
  288. {
  289.   LedSpacing = spacing;
  290.   LedThick = thickPercent;
  291. }
  292.  
  293. //
  294. // If using a system control, update it to match our member settings
  295. //
  296. void
  297. TGauge::SetupWindow()
  298. {
  299.   TControl::SetupWindow();
  300.   if (NativeUse & nuUsing) {
  301.     SendMessage(PBM_SETRANGE, 0, MkParam2(Min, Max));
  302.     SendMessage(PBM_SETSTEP, Step);
  303.     SendMessage(PBM_SETPOS, Value);
  304.   } 
  305. }
  306.  
  307. //
  308. // Paint the border-- bevel & margin
  309. //
  310. void
  311. TGauge::PaintBorder(TDC& dc)
  312. {
  313.   int   xBorder = TUIMetric::CxBorder;
  314.   int   yBorder = TUIMetric::CyBorder;
  315.   TRect cr(GetClientRect());
  316.   int   w = cr.right;
  317.   int   h = cr.bottom;
  318.  
  319.   TBrush shadowBrush(TColor::Sys3dShadow);
  320.   dc.SelectObject(shadowBrush);
  321.   dc.PatBlt(0, 0, w, yBorder);
  322.   dc.PatBlt(0, yBorder, xBorder, h-yBorder);
  323.  
  324.   TBrush hiliteBrush(TColor::Sys3dHilight);
  325.   dc.SelectObject(hiliteBrush);
  326.   dc.PatBlt(xBorder, h-yBorder, w-xBorder, h-yBorder);
  327.   dc.PatBlt(w-xBorder, yBorder, xBorder, h-yBorder-yBorder);
  328.  
  329.   TBrush  faceBrush(TColor::Sys3dFace);
  330.   TRect   innerRect(xBorder, yBorder, w-xBorder, h-yBorder);
  331.  
  332.   // Walk in from the bevel painting frames as we go
  333.   //
  334.   for (int i = 0; i < Margin; i++) {
  335.     dc.FrameRect(innerRect, faceBrush);
  336.     innerRect.Inflate(-1, -1);
  337.   }
  338. }
  339.  
  340. //
  341. // Paint the whole gauge: border & graphic
  342. //
  343. void
  344. TGauge::Paint(TDC& dc, bool /*erase*/, TRect&)
  345. {
  346.   PaintBorder(dc);
  347.  
  348.   // Prepare to paint the bar or LED sequence in the well
  349.   //
  350.   int    xBorder = TUIMetric::CxBorder;
  351.   int    yBorder = TUIMetric::CyBorder;
  352.   TRect cr(GetClientRect());
  353.   int   w = cr.right;
  354.   int   h = cr.bottom;
  355.  
  356.   TBrush  barBrush(BarColor);
  357.   TBrush  faceBrush(TColor::Sys3dFace);
  358.   TRect   innerRect(xBorder+Margin, yBorder+Margin,
  359.                     w-xBorder-Margin, h-yBorder-Margin);
  360.  
  361.   // Draw either LEDs or a solid bar as indicated by LedSpacing
  362.   //
  363.   if (LedSpacing) {
  364.     if (IsHorizontal) {
  365.       int ledStep = (innerRect.Width()*LedSpacing)/(Max-Min);
  366.       int ledWidth = (ledStep*LedThick)/100;
  367.       int gapWidth = ledStep - ledWidth;
  368.       int x = innerRect.left;
  369.       int right = innerRect.left +
  370.                   int((long(Value-Min)*innerRect.Width())/(Max-Min));
  371.       for (; x < right; x += ledStep) {
  372.         dc.FillRect(x, innerRect.top, x+ledWidth, innerRect.bottom, barBrush);
  373.         dc.FillRect(x+ledWidth, innerRect.top, x+ledWidth+gapWidth, innerRect.bottom, faceBrush);
  374.       }
  375.       dc.FillRect(x, innerRect.top, innerRect.right, innerRect.bottom, faceBrush);
  376.     }
  377.     else {
  378.       int ledStep = int((long(innerRect.Height())*LedSpacing)/(Max-Min));
  379.       int ledHeight = int((long(ledStep)*LedThick)/100);
  380.       int gapHeight = ledStep - ledHeight;
  381.       int y = innerRect.bottom;
  382.       int top = innerRect.top + innerRect.Height() -
  383.                 int((long(Value-Min)*innerRect.Height())/(Max-Min));
  384.       for (; y > top; y -= ledStep) {
  385.         dc.FillRect(innerRect.left, y-ledHeight, innerRect.right, y, barBrush);
  386.         dc.FillRect(innerRect.left, y-ledHeight-gapHeight, innerRect.right, y-ledHeight, faceBrush);
  387.       }
  388.       dc.FillRect(innerRect.left, innerRect.top, innerRect.right, y, faceBrush);
  389.     }
  390.   }
  391.   else {
  392.     TRect barRect(innerRect);
  393.     TRect emptyRect(innerRect);
  394.     if (IsHorizontal) {
  395.       int w = int((long(Value-Min)*innerRect.Width())/(Max-Min));
  396.       barRect.right = emptyRect.left = innerRect.left+w;
  397.     }
  398.     else {
  399.       int h = innerRect.Height() -
  400.               int((long(Value-Min)*innerRect.Height())/(Max-Min));
  401.       barRect.top = emptyRect.bottom = innerRect.top+h;
  402.     }
  403.     dc.FillRect(emptyRect, faceBrush);
  404.     dc.FillRect(barRect, barBrush);
  405.  
  406.     if (Title && *Title) {
  407.       char buff[32];
  408.       wsprintf(buff, Title, Value);  
  409.  
  410.       int   len = strlen(buff);
  411.       TSize extent = dc.GetTextExtent(buff, len);
  412.       int   x = innerRect.left;
  413.       int   y = innerRect.top;
  414.  
  415.       if (extent.cx < innerRect.Width())
  416.         x += (innerRect.Width() - extent.cx) / 2;  // center text horizontally
  417.  
  418.       if (extent.cy < innerRect.Height())
  419.         y += (innerRect.Height() - extent.cy) / 2; // center text vertically
  420.  
  421.       // use ExtTextOut() to paint the text in contrasting colors to the bar
  422.       // and background
  423.       //
  424.       dc.SetBkMode(TRANSPARENT);
  425.       dc.SetTextColor(TColor::Sys3dFace);
  426.       dc.ExtTextOut(x, y, ETO_CLIPPED, &barRect, buff, strlen(buff));
  427.       dc.SetTextColor(BarColor);
  428.       dc.ExtTextOut(x, y, ETO_CLIPPED, &emptyRect, buff, strlen(buff));
  429.     }
  430.   }
  431. }
  432.  
  433. //
  434. // We'll always erase as we paint to avoid flicker
  435. //
  436. bool
  437. TGauge::EvEraseBkgnd(HDC)
  438. {
  439.   if (NativeUse & nuUsing)
  440.     return DefaultProcessing();
  441.   else
  442.     return true;
  443. }
  444.